package app.server.project.main.service.service.race;

import app.server.project.core.constants.Def;
import app.server.project.core.http.CMSLstResp;
import app.server.project.main.service.bo.event.AddRaceValEvent;
import app.server.project.main.service.bo.event.ConsumeRaceValEvent;
import app.server.project.main.service.bo.event.PassEvent;
import app.server.project.main.service.bo.event.RejectEvent;
import app.server.project.main.service.db.dao.user.UserActiveRewardDao;
import app.server.project.main.service.db.dao.user.UserRaceDao;
import app.server.project.main.service.db.dao.user.UserRaceDetailDao;
import app.server.project.main.service.db.entity.user.UserActiveRewardEntity;
import app.server.project.main.service.db.entity.user.UserRaceDetailEntity;
import app.server.project.main.service.dto.cms.CoinDto;
import app.server.project.main.service.dto.race.GetUserRaceDetailReq;
import app.server.project.main.service.dto.race.GetUserRaceDetailResp;
import app.server.project.main.service.service.ResService;
import app.server.project.main.service.service.upay.BalanceService;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.IdUtil;
import lombok.AllArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.Objects;

@AllArgsConstructor
@Service
public class UserRaceDetailService {

    private final static long PageSize = 200;
    private final UserRaceDetailDao userRaceDetailDao;
    private final UserRaceDao userRaceDao;
    private final UserActiveRewardDao userActiveRewardDao;
    private final ResService resService;
    private final BalanceService balanceService;


    public GetUserRaceDetailResp getAllUserRaceDetail(long userId, GetUserRaceDetailReq req) {
        var db = this.userRaceDetailDao.getLastData(userId, PageSize, 1, req.getRaceId());
        db.forEach(v -> {
            var type = EnumUtil.getBy(DetailType.class, p -> p.getType() == v.getDetailType());
            if (Objects.nonNull(type)) {
                v.setDetailTypeStr(type.getDes());
            }
            var status = EnumUtil.getBy(DetailStatusType.class, p -> p.getType() == v.getStatus());
            if (Objects.nonNull(status)) {
                v.setDetailStatusStr(status.getDes());
            }
        });
        return GetUserRaceDetailResp.of(req.getPageIndex(), req.getRaceId(), db, PageSize);
    }

    @EventListener(classes = AddRaceValEvent.class)
    public void onAddRaceValEvent(AddRaceValEvent event) {
        var db = UserRaceDetailEntity.ofAddType(
                IdUtil.getSnowflakeNextId(),
                event.getUserId(),
                event.getDetailType(),
                event.getRaceCfg(),
                event.getVal());
        db.setBlockType(event.getBlockType());
        var cache = this.userRaceDetailDao.getLastData(event.getUserId(), PageSize, 1, event.getRaceCfg().getId());
        cache.add(Def.Zero, db);
        if (PageSize >= cache.size()) {
            return;
        }
        var nonCache = cache.subList((int) PageSize, cache.size());
        nonCache.forEach(v -> v.setIsDel(Def.True));
        cache.removeAll(nonCache);
    }

    @EventListener(classes = ConsumeRaceValEvent.class)
    public void onConsumeRaceValEvent(ConsumeRaceValEvent event) {
        var db = UserRaceDetailEntity.ofConsumeType(
                event.getDetailId(),
                event.getUserId(),
                event.getDetailType(),
                event.getRaceCfg(),
                event.getVal());
        db.setBlockType(event.getBlockType());
        var cache = this.userRaceDetailDao.getLastData(event.getUserId(), PageSize, 1, event.getRaceCfg().getId());
        cache.add(Def.Zero, db);
        if (PageSize >= cache.size()) {
            return;
        }
        var nonCache = cache.subList((int) PageSize, cache.size());
        nonCache.forEach(v -> v.setIsDel(Def.True));
        cache.removeAll(nonCache);
    }

    @EventListener(classes = PassEvent.class)
    public void onPass(PassEvent event) {
        var cache = this.userRaceDetailDao.getLastData(event.getUserId(), PageSize, 1, event.getRaceId());
        if (cache.stream().anyMatch(v -> v.getId() == event.getDetailId())) {
            cache.forEach(v -> {
                if (v.getId() == event.getDetailId()) {
                    v.setStatus(DetailStatusType.Credited.getType());
                }
            });
        } else {
            var ret = new UserRaceDetailEntity();
            ret.setId(event.getDetailId());
            ret.setSynDb(true);
            ret.setStatus(DetailStatusType.Credited.getType());
        }
    }

    @EventListener(classes = RejectEvent.class)
    public void onReject(RejectEvent event) {
        var cache = this.userRaceDetailDao.getLastData(event.getUserId(), PageSize, 1, event.getRaceId());
        if (cache.stream().anyMatch(v -> v.getId() == event.getDetailId())) {
            cache.forEach(v -> {
                if (v.getId() == event.getDetailId()) {
                    v.setStatus(DetailStatusType.Denied.getType());
                }
            });
        } else {
            var ret = new UserRaceDetailEntity();
            ret.setId(event.getDetailId());
            ret.setSynDb(true);
            ret.setStatus(DetailStatusType.Denied.getType());
        }
        switch (event.getRaceId()) {
            case CoinType.TON_COIN: {
                UserActiveRewardEntity userActiveRewardEntity = this.userActiveRewardDao.getInfoById(event.getUserId());
                userActiveRewardEntity.addTonVal(event.getVal());
            }
            break;
            case CoinType.USDT_COIN: {
                this.balanceService.addBalance(event.getUserId(), event.getVal());
            }
            break;
            default: {
                this.resService.addResNum(event.getUserId(), event.getRaceId(), event.getVal(), true);
            }
            break;
        }
    }


    public CMSLstResp<CoinDto> getCoins() {
        var ret = this.userRaceDao.getBaseMapper().sumCoin();
        return CMSLstResp.of(ret, ret.size());
    }
}
